#!/bin/bash
# /**
# * Copyright (c) 2018, yzfcer@163.com
# * All rights reserved.
# * @file    file_filter.sh
# * @brief   查看符合规则的文件
# * @author  Jason Zhou,yzfcer@163.com
# * @version 1.0
# * @date    2021-09-15
# */

# Global variables
declare -a find_conditions
max_depth=""
include_hidden=false
include_empty=false
target_dir=""

show_help() {
    cat <<EOF
File Filter Utility - Advanced recursive file search

Usage: $0 <directory> [options]

Options:
  -n, --name <pattern>    Match exact filename (supports '|' for multiple patterns)
  -t, --type <extensions> Match file extensions (e.g. 'c|h|C|H')
  -s, --start <prefixes>  Match filename prefixes (e.g. 'sw|st')
  -e, --end <suffixes>    Match filename suffixes (e.g. 'bak|tmp')
  -m, --middle <text>     Match text anywhere in filename
  --max-size <size>       Match files smaller than <size> (e.g. 1M, 500k)
  --min-size <size>       Match files larger than <size>
  -d, --max-depth <N>     Maximum search depth (default: unlimited)
  --hidden                Include hidden files
  --empty                 Include empty files
  -h, --help              Show this help

Examples:
  $0 ./src -t 'c|h'       # Find all .c/.h files recursively
  $0 /tmp -n '*.tmp' -d 1 # Find .tmp files only in /tmp (no subdirs)
  $0 . -m 'config'        # Find files containing 'config'
EOF
}

add_condition() {
    find_conditions+=("$@")
}

parse_size() {
    [[ $1 =~ ^[0-9]+[kMGTP]?$ ]] && echo "$1" || {
        echo "Error: Invalid size format '$1'" >&2
        exit 1
    }
}

parse_patterns() {
    local patterns="$1"
    local find_test="$2"
    local transform="$3"

    IFS='|' read -ra parts <<< "$patterns"
    local conditions=()

    for part in "${parts[@]}"; do
        case "$transform" in
            type) part="*.$part" ;;
            start) part="$part*" ;;
            end) part="*$part.*" ;;
            *) part="*$part*" ;;
        esac
        conditions+=("$find_test" "$part")
    done

    if [[ ${#conditions[@]} -gt 2 ]]; then
        add_condition "(" "${conditions[@]}" ")"
    else
        add_condition "${conditions[@]}"
    fi
}

parse_arguments() {
    [[ $# -eq 0 ]] && { show_help; exit 0; }

    while [[ $# -gt 0 ]]; do
        case "$1" in
            -h|--help) show_help; exit 0 ;;
            -n|--name) parse_patterns "$2" "-name"; shift 2 ;;
            -t|--type) parse_patterns "$2" "-name" "type"; shift 2 ;;
            -s|--start) parse_patterns "$2" "-name" "start"; shift 2 ;;
            -e|--end) parse_patterns "$2" "-name" "end"; shift 2 ;;
            -m|--middle) parse_patterns "$2" "-name"; shift 2 ;;
            --max-size) add_condition "-size" "-$(parse_size "$2")"; shift 2 ;;
            --min-size) add_condition "-size" "+$(parse_size "$2")"; shift 2 ;;
            -d|--max-depth) max_depth="$2"; shift 2 ;;
            --hidden) include_hidden=true; shift ;;
            --empty) include_empty=true; add_condition "-empty"; shift ;;
            -*) echo "Error: Unknown option '$1'" >&2; exit 1 ;;
            *) target_dir="${target_dir:-$1}"; shift ;;
        esac
    done
}

main() {
    parse_arguments "$@"
    target_dir="${target_dir:-.}"
    target_dir="$(realpath "$target_dir" 2>/dev/null || echo "$target_dir")"

    [[ ! -d "$target_dir" ]] && {
        echo "Error: Directory '$target_dir' does not exist" >&2
        exit 1
    }

    # Build find command
    local find_cmd=("find" "$target_dir")
    [[ -n "$max_depth" ]] && find_cmd+=("-maxdepth" "$max_depth")
    "$include_hidden" || find_cmd+=("!" "-path" "*/.*")
    find_cmd+=("-type" "f")
    [[ ${#find_conditions[@]} -gt 0 ]] && find_cmd+=("${find_conditions[@]}")
    find_cmd+=("-print")

    # Execute command
    "${find_cmd[@]}" 2>/dev/null
}

main "$@"
